package myerrors

import (
	"encoding/json"
	"fmt"
	"runtime"
	"strings"
)

type MyError struct {
	Id       int
	Msg      string
	InnerMsg string
	Err      error
}

func (e *MyError) Error() string {
	return e.Msg
}

func (e *MyError) String() string {
	s, _ := json.Marshal(e)
	return string(s)
}
func (e *MyError) FullMsg() string {
	var r = e.Msg + e.InnerMsg
	if e.Err != nil {
		r += e.Err.Error()
	}
	return r
}

/**
*判断是不是自定义err
*返回code 0 代表非自定义
 */
func GetMyError(err any) MyError {
	switch x := err.(type) {
	case MyError:
		return err.(MyError)

	case *MyError:
		return *x
	case error:
		{
			var cal = GetCallInfo()
			fmt.Println(cal)
			return MyError{
				Id:       ERROR_UNKNOW,
				Msg:      "未知异常",
				InnerMsg: err.(error).Error(),
			}
		}
	default:
		{
			return MyError{
				Id:       ERROR_UNKNOW,
				Msg:      "未知异常",
				InnerMsg: err.(string),
			}
		}
		break
	}
	return MyError{
		Id:       ERROR_UNKNOW,
		Msg:      "未知异常",
		InnerMsg: fmt.Sprint(err),
	}
}

/**
*创建可显示信息
*返回code 0 代表非自定义
 */
func New(msg string) *MyError {
	var r = MyError{
		Id:  ERROR_MSG,
		Msg: msg,
	}
	return &r
}

/**
*判断是不是自定义err
*返回code 0 代表非自定义
 */
func NewByCode(code int, msg ...string) *MyError {
	var Msg = ""
	if len(msg) != 0 {
		Msg = strings.Join(msg, "\r\n")
	}
	if "" == Msg {
		if ERROR_DATANOTEXIST == code {
			Msg = "数据不存在"
		}
	}
	var r = MyError{
		Id:  code,
		Msg: Msg,
	}

	return &r
}

/**
*创建err对于异常
*
 */
func NewByErr(err error, msg ...string) *MyError {
	var InnerMsg = ""
	if len(msg) != 0 {
		InnerMsg = strings.Join(msg, "\r\n")
	}
	switch x := err.(type) {
	case *MyError:
		return x
	default:
		break
	}

	var s = GetCallInfo()
	var r = MyError{
		Id:       ERROR_UNKNOW,
		Msg:      "未知异常",
		InnerMsg: InnerMsg + s,
		Err:      err,
	}
	return &r
}

/**
*创建数据不存在异常
*
 */
func NewDataNotExist() *MyError {
	return NewByCode(ERROR_DATANOTEXIST)
}

func GetCallInfo() string {
	pc := make([]uintptr, 10)   // 创建一个切片存放程序计数器地址
	n := runtime.Callers(2, pc) // 从当前位置开始递归查询调用者的PC值
	var r = ""
	for i := 0; i < n; i++ {
		fn := runtime.FuncForPC(pc[i]) // 根据PC值获取对应的函数名称
		if fn == nil {
			continue
		}

		// 打印文件路径、行号和函数名称
		file, line := fn.FileLine(pc[i])
		r += fmt.Sprintf("File: %s\t Line: %d\t Function: %s\n", file, line, fn.Name())
	}
	return r
}

const (
	ERROR_DATANOTEXIST = 110
	ERROR_MSG          = 100
	ERROR_UNKNOW       = 99
	ERROR_PInError     = 10
	ERROR_BADREQUEST   = 400
	ERROR_UNAUTHORIZED = 401
)
